package com.guoyh.baseutils.mylog;

import android.util.Log;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.Locale;


/**
 *
 *
 * setprop log.tag.{@link #PRIVATE_TAG} LOG_LEVEL
 * Created by GUO_YH on 2018/11/27 15:31
 *
 *
 * eg: Logger.v("%s %s %d + %d  = %d,","TAG","Hello: ",5,6,11)
 * will print "TAG Hello: 5 + 6 = 11"
 *
 * adb shell setprop log.tag.这里填tag 这里是log等级(DEBUG)
 * adb shell setprop log.tag.guoyhTag_private DEBUG
 */


public class Loger {

    private static final String SIMPLE_PREFIX = "[(%s:%d)#%s()] ->  ";
    private static final String MORE_DETAIL_PREFIX = "at %s.%s(%s:%d)";
    private static final StringBuffer mMessageBuffer = new StringBuffer();

    //不可以是中文 不能改动 否则后续的adb 会失效
    private static String PRIVATE_TAG = "guoyhTag_private";
    private static String PUBLIC_TAG = "guoyhTag_public";


    public static boolean mDebugable = true;


    public  static boolean DEBUG_V = Log.isLoggable(PRIVATE_TAG, Log.VERBOSE);

    private static boolean DEBUG_MORE_DETAIL_STACK_INFO = false;
    private static int  STACK_TRACE_INDEX = 5;
    private static final String SUFFIX = ".java";
    private static final String myFormat = "Android_MTag======>>>>%s";


    public static boolean isAdbDebug_D(){
        return Log.isLoggable(PRIVATE_TAG, Log.DEBUG);
    }

    /**
     * 正式发布产品的时候应该关闭debug 模式
     * @param debug 设置Log 模式，如果true 表示debug模式该模式可以从控制台查看相关log信息，否则不是
     */
    public static void setDebug(boolean debug) {
        mDebugable = debug;
    }

    public static synchronized void v(String format, Object... args) {

        if(mDebugable){
            log(Log.VERBOSE,buildPrivateMessage(null,format, args));
        }else{
            if(DEBUG_V){
                log(Log.VERBOSE,buildPrivateMessage(null,format, args));
            }
        }

    }

    /**
     * 级别最低，用于输出任意对调试或者开发过程中有帮助的信息,
     *
     * @param format the format string (see {@link java.util.Formatter#format})
     * @param args   the list of arguments passed to the formatter. If there are
     *               more arguments than required by {@code format},
     *               additional arguments are ignored.
     */

    public static synchronized void v(Throwable throwable, String format, Object... args) {

        if(mDebugable){
            log(Log.VERBOSE,buildPrivateMessage(throwable,format, args));
        }else{
            if(DEBUG_V){
                log(Log.VERBOSE,buildPrivateMessage(throwable,format, args));
            }
        }

    }

    public static synchronized void d(String format, Object... args) {
        if(mDebugable){
            log(Log.DEBUG,buildPrivateMessage(null,format, args));
        }else{
            if(isAdbDebug_D()){
                log(Log.DEBUG,buildPrivateMessage(null,format, args));
            }
        }

    }

    public static synchronized void dd(Object... args) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < args.length; i++) {
            sb.append("【"+args[i]+"】");
            if (i != args.length-1){
                sb.append("======>>>>");
            }
        };

        if(mDebugable){
            log(Log.DEBUG,buildPrivateMessage(null,myFormat, sb));
        }else{
            if(isAdbDebug_D()){
                log(Log.DEBUG,buildPrivateMessage(null,myFormat, sb));
            }
        }

    }

    /**
     * 调试级别, 比VERBOSE高，用于输出调试信息
     *
     * @param format the format string (see {@link java.util.Formatter#format})
     * @param args   the list of arguments passed to the formatter. If there are
     *               more arguments than required by {@code format},
     *               additional arguments are ignored.
     */

    public static synchronized void d(Throwable throwable, String format, Object... args) {


        if(mDebugable){
            log(Log.DEBUG,buildPrivateMessage(throwable,format, args));
        }else{
            if(isAdbDebug_D()){
                log(Log.DEBUG,buildPrivateMessage(throwable,format, args));
            }
        }
    }
    public static void ddd(String tag, String msg) {
        if(mDebugable){
            //信息太长,分段打印
            //因为String的length是字符数量不是字节数量所以为了防止中文字符过多，
            //  把4*1024的MAX字节打印长度改为2001字符数
            int max_str_length = 2001 - tag.length();
            //大于4000时
            while (msg.length() > max_str_length) {
                Log.d(tag, msg.substring(0, max_str_length));
                msg = msg.substring(max_str_length);
            }
            //剩余部分
            Log.d(tag, msg);
        }else{
            if(isAdbDebug_D()){
                //信息太长,分段打印
                //因为String的length是字符数量不是字节数量所以为了防止中文字符过多，
                //  把4*1024的MAX字节打印长度改为2001字符数
                int max_str_length = 2001 - tag.length();
                //大于4000时
                while (msg.length() > max_str_length) {
                    Log.d(tag, msg.substring(0, max_str_length));
                    msg = msg.substring(max_str_length);
                }
                //剩余部分
                Log.d(tag, msg);
            }
        }


    }
    /**
     * 用于输出比较重要的信息，系统默认的级别，
     *
     * @param format the format string (see {@link java.util.Formatter#format})
     * @param args   the list of arguments passed to the formatter. If there are
     *               more arguments than required by {@code format},
     *               additional arguments are ignored.
     */
    public static void i(String format, Object... args) {
        Log.i(PUBLIC_TAG, buildPrivateMessage(null,format, args));
    }
    public static void ii(String format, Object... args) {
        Log.i(PUBLIC_TAG, buildPrivateMessage(null,myFormat, args));
    }

    public static void i(Throwable throwable, String format, Object... args) {

        Log.i(PUBLIC_TAG, buildPrivateMessage(null,format, args), throwable);
    }

    public static void w(String format, Object... args) {
        Log.w(PUBLIC_TAG, buildPrivateMessage(null,format, args));

    }

    public static void w(Throwable throwable, String format, Object... args) {
        Log.w(PUBLIC_TAG, buildPrivateMessage(throwable,format, args), throwable);
    }

    public static void e(String format, Object... args) {
        Log.e(PUBLIC_TAG, buildPrivateMessage(null,format, args));
    }
    public static void ee(Object... args) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < args.length; i++) {
            sb.append("【"+args[i]+"】");
            if (i != args.length-1){
                sb.append("======>>>>");
            }
        };
        Log.e(PUBLIC_TAG, buildPrivateMessage(null,myFormat, sb));
    }
    public static void e(Throwable throwable, String format, Object... args) {
        Log.e(PUBLIC_TAG, buildPrivateMessage(null,format, args), throwable);
    }



    public static final String LINE_SEPARATOR = System.getProperty("line.separator");

    private static void printLine( boolean isTop) {
        if (isTop) {
            dd( "╔═══════════════════════════════════════════════════════════════════════════════════════");
        } else {
            dd( "╚═══════════════════════════════════════════════════════════════════════════════════════");
        }
    }
    public static void json(String msg){
        json(msg,"Json:");
    }
    public static void json( String msg, String headString) {

        if (!mDebugable){
            return;
        }
        String message;

        try {
            if (msg.startsWith("{")) {
                JSONObject jsonObject = new JSONObject(msg);
                message = jsonObject.toString(4);//最重要的方法，就一行，返回格式化的json字符串，其中的数字4是缩进字符数
            } else if (msg.startsWith("[")) {
                JSONArray jsonArray = new JSONArray(msg);
                message = jsonArray.toString(4);
            } else {
                message = msg;
            }
        } catch (JSONException e) {
            message = msg;
        }

        printLine( true);
        message = headString + LINE_SEPARATOR + message;
        String[] lines = message.split(LINE_SEPARATOR);
        for (String line : lines) {
            Log.d( "guoyh"+headString,"║ " + line);
        }
        printLine( false);
    }

//    public String formatJson(String json){
//        return LogJsonFormat.format(json);
//    }


    private static String getSimpleStackTrace(){
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        StackTraceElement targetElement = stackTrace[STACK_TRACE_INDEX];
        return  String.format(Locale.getDefault(),SIMPLE_PREFIX,targetElement.getFileName(),targetElement.getLineNumber(),targetElement.getMethodName());
    }

    public static String getMoreDetailStackTrace() {
        StackTraceElement[] traceElements = Thread.currentThread().getStackTrace();
        StringBuilder builder = new StringBuilder();
        for (int i = STACK_TRACE_INDEX; i < Math.min(traceElements.length, 10); i++) {
            StackTraceElement traceElement = traceElements[i];
            builder.append(String.format(Locale.getDefault(), MORE_DETAIL_PREFIX, traceElement.getClassName(),
                    traceElement.getMethodName(), traceElement.getFileName(), traceElement.getLineNumber()));
            builder.append("\n");
        }
        return builder.toString();
    }


    private static String buildPrivateMessage(Throwable throwable, String format, Object... args) {
        mMessageBuffer.delete(0, mMessageBuffer.length());

        try {
            mMessageBuffer.append("{ ");

            mMessageBuffer.append(getSimpleStackTrace());

            mMessageBuffer.append((args == null) ? format : String.format(Locale.CHINA, format, args));
        } catch (Exception e) {
            mMessageBuffer.append("buildPrivateMessage exception " + e.getMessage());
        }

        if(DEBUG_MORE_DETAIL_STACK_INFO){
            mMessageBuffer.append("\n");
            mMessageBuffer.append(getMoreDetailStackTrace());
            mMessageBuffer.append("\n");
        }
        if(throwable != null){

            mMessageBuffer.append(throwable.toString());
            mMessageBuffer.append("\n");
        }
        mMessageBuffer.append(" } \n");


        return mMessageBuffer.toString();
    }









    public static String isNull(Object o) {
        return o == null ? " Null" : "Not Null";
    }

    public static String toStringOb(Object o) {
        return o == null ? " Null" : o.toString();
    }

    private static  boolean isEnableDebug(){
        if(!mDebugable){
            return false;
        }

        if(!DEBUG_V){
            return false;
        }

        return true;
    }

    private static void log(int level, String mes){
        if(mes.length() > 4000){
            for(int i = 0 ; i < mes.length(); i += 4000 ){
                if( i + 4000 < mes.length()){

                    println(level,mes.substring(i,i + 4000));
                }else{
                    println(level,mes.substring(i,mes.length()));
                }

            }
        }else{
            println(level,mes);
        }
    }


    private static void println(int level, String mes){

        switch (level){
            case Log.ERROR:
                Log.e(PRIVATE_TAG,mes);
                break;
            case Log.WARN:
                Log.w(PRIVATE_TAG,mes);
                break;
            case Log.INFO:
                Log.i(PRIVATE_TAG,mes);
                break;
            case Log.DEBUG:
                Log.d(PRIVATE_TAG,mes);
                break;
            case Log.VERBOSE:
                Log.v(PRIVATE_TAG,mes);
                break;
        }
    }
}
